/*
*******************************************************************************
* ansi c source code
* file name:
*	Jake.c
* abstract: 
*	to generate a Jake's model for multipath fading channel
* reference:
*	
* author:Fangming He
*******************************************************************************
*/


/*
*******************************************************************************
*                               include files
*******************************************************************************
*/
#include <math.h>
#include "JakeType.h"


/*
*******************************************************************************
*			           constants and define declarations
*******************************************************************************
*/
#define PI	3.141592653589793


/*
*******************************************************************************
* 		                    global object definition
*******************************************************************************
*/
/* local variables used in the random function RunRandJake() */
long	jake_rand_seed = 19;
long	jake_rand_x;
long	jake_rand_y;
long	jake_rand_z;
int		jake_rand_cnt = 0;


/*
*******************************************************************************
*                            function definition
*******************************************************************************
*/
/*
*******************************************************************************
* description:
*	to produce uniform iid sequence within [0.0 1.0)
* input: 
*	none
* output:
*	return: a uniformly distributed number within [0.0 1.0)
* function reference:
* author:
*	guo liang, 2004-08-24	created
*******************************************************************************
*/
double RunRandJake(void)
{
	double	result;
	
	if ( jake_rand_cnt == 0 )
	{
		jake_rand_x = jake_rand_seed;
		jake_rand_y = jake_rand_seed;
		jake_rand_z = jake_rand_seed;
		jake_rand_cnt++ ;
	}

	jake_rand_x = (jake_rand_x * 249) % 61967;
	jake_rand_y = (jake_rand_y * 251) % 63443;
	jake_rand_z = (jake_rand_z * 252) % 63599;
	result = (jake_rand_x/61967.0 + jake_rand_y/63443.0 + jake_rand_z/63599.0) - (int)(jake_rand_x/61967.0 + jake_rand_y/63443.0 + jake_rand_z/63599.0);

	return result;
}


/*
******************************************************************************* 
* discription:
*	set and initialize variables for Jake's Model
* input: 
*	p_jake: pointer to a structure of Jake type
*	osci_num: number of the oscillators used in the Jake's model
*	sample_rate: rate of sampling (Hz)
*	fd_max: maximun Doppler frequence (Hz)
*	var: variance of inphase and quadrature components
* output:
*	invalid input indication (1 - OK, 0 - WRONG)
* function reference: 
* author:
*	guo liang, 2006-05-04	created
*	guo liang, 2006-05-08	revised
*	guo liang, 2005-03-14	revised
*******************************************************************************
*/
int SetJake(JakeSt *p_jake, int osci_num, double sample_rate, double fd_max, double var)
{
	int		n;		/* a counter */
	int		m_osci;	/* number of oscillators with partial doppler frequency */
	double	dev;	/* deviation of inphase and quadrature components */
	double	wd_max;	/* maximun doppler angle velocity */


	/* check the input parameters */
	if ( (osci_num < 1) || (osci_num > MAX_OSCI_NUM) )
	{
		return 0;
	}

	if ( (sample_rate <= 0) || (fd_max < 0) || (var < 0) )
	{
		return 0;
	}


	/* calculate deviation */
	dev = sqrt(var);

	/* set the number of oscillators */
	p_jake->osci_num = osci_num;
	m_osci = osci_num - 1;

	/* set the rate of sampling */
	p_jake->sample_rate = sample_rate;

	/* set maximun Doppler frequence */
	p_jake->fd_max = fd_max;
	wd_max = 2 * PI * fd_max;

	/* set model time */
	p_jake->time = 0;
	p_jake->time_step = 1.0 / sample_rate;


	/* calculate coefficients of the cosine function of the inphase and quadrature components */
	p_jake->cos_coef_i[0] = 1;
	p_jake->cos_coef_q[0] = 1;
	for (n = 1; n <= m_osci; n++)
	{
		p_jake->cos_coef_i[n] = 2 * cos(PI*n/m_osci);
		p_jake->cos_coef_q[n] = 2 * sin(PI*n/m_osci);
	}
	for (n = 0; n < osci_num; n++)
	{
		p_jake->cos_coef_i[n] *= (dev * sqrt(2) / sqrt(2*m_osci + 1));
		p_jake->cos_coef_q[n] *= (dev * sqrt(2) / sqrt(2*m_osci + 1));
	}


	/* calculate doppler angle velocities in the cosine function */
	p_jake->wd[0] = wd_max;
	for (n = 1; n <= m_osci; n++)
	{
		p_jake->wd[n] = wd_max * cos(PI*n/(2*m_osci+1));
	}
	

	/* generate the initial phases in the cosine function */
	p_jake->init_phase[0] = 2 * PI * RunRandJake();
	for (n = 1; n <= m_osci; n++)
	{
		p_jake->init_phase[n] = 2 * PI * RunRandJake();
	}

	return 1;
}


/*
******************************************************************************* 
* discription:
*	initialize variables used in jake's model
* input: 
*	p_jake: pointer to a structure of Jake type
* output:
*	none
* function reference: 
* author:
*	guo liang, 2005-03-14	created
*******************************************************************************
*/
void InitJake(JakeSt *p_jake)
{
	p_jake->time = 0;
}


/*
******************************************************************************* 
* discription:
*	run the Jake's model and output a complex fading coefficient
* input:
*	p_jk: pointer to a structure of one Jake's model
* output:
*	*p_coef_i: the inphase    coefficient of the jake's fader
*	*p_coef_q: the quadrature coefficient of the jake's fader
* function reference: 
* author:
*	guo liang, 2006-05-04	created
*	guo liang, 2006-05-08	revised
*******************************************************************************
*/
void RunJake(JakeSt *p_jake, double *p_coef_i, double *p_coef_q)
{
	int		n;

	/* compute inphase and quadrature components */
	(*p_coef_i) = 0;
	(*p_coef_q) = 0;
	for (n = 0; n < p_jake->osci_num; n++)
	{
		(*p_coef_i) += p_jake->cos_coef_i[n] * cos(p_jake->wd[n] * p_jake->time + p_jake->init_phase[n]);
		(*p_coef_q) += p_jake->cos_coef_q[n] * cos(p_jake->wd[n] * p_jake->time + p_jake->init_phase[n]);
	}

	/* add model time */
	p_jake->time += p_jake->time_step;
}

